/* Classic Ladder Project */
/* Copyright (C) 2001-2012 Marc Le Douarain */
/* http://membres.lycos.fr/mavati/classicladder/ */
/* http://www.sourceforge.net/projects/classicladder */
/* February 2001 */
/* --------------------------- */
/* Alloc/free global variables */
/* --------------------------- */
/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef MODULE
#include <stdio.h>
#include <stdlib.h>
#endif

#ifndef RT_SUPPORT
#include <signal.h>
#else
#include <linux/string.h>
#endif

#include "classicladder.h"
#include "files.h"
#include "calc.h"
#include "vars_access.h"
#include "manager.h"
#include "calc_sequential.h"
#include "symbols.h"
#include "vars_system.h"
#include "protocol_modbus_master.h"
#ifdef COMPLETE_PLC
#include "log_events.h"
#endif
#include "tasks.h"
#include "hardware.h"

#if defined( MODULE )
#include <linux/string.h>
#include "module_rtlinux.h"
#else
#include <string.h>
#endif

#ifdef GTK_INTERFACE
#include <gtk/gtk.h>
#include "classicladder_gtk.h"
#include "manager_gtk.h"
#include "symbols_gtk.h"
//#include <gtk/gtk.h>
#endif

#ifdef MAT_CONNECTION
#include "../../lib/plc.h"
#endif


#if defined( RTLINUX ) || defined ( __RTL__ )
#include "/usr/rtlinux/include/mbuff.h"
#endif

#if defined(RTAI)
#if !defined(MODULE)
#include <stddef.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include "rtai.h"
#include "rtai_shm.h"
#define mbuff_alloc(a, b) rtai_malloc(nam2num(a), b)
#define mbuff_free(a, b) rtai_free(nam2num(a), b)
#else
#include <linux/module.h>
#include "rtai.h"
#include "rtai_shm.h"
#define mbuff_alloc(a, b) rtai_kmalloc(nam2num(a), b)
#define mbuff_free(a, b) rtai_kfree(nam2num(a))
#endif
#endif

StrRung * RungArray;
TYPE_FOR_BOOL_VAR * VarArray;
unsigned char * LogVarArray;
int * VarWordArray;
#ifdef OLD_TIMERS_MONOS_SUPPORT
StrTimer * TimerArray;
StrMonostable * MonostableArray;
#endif
StrCounter * CounterArray;
StrTimerIEC * NewTimerArray;
StrArithmExpr * ArithmExpr;
StrInfosGene * InfosGene;
StrInfosGUI * InfosGUI;
StrSection * SectionArray;
#ifdef SEQUENTIAL_SUPPORT
StrSequential * Sequential;
#endif
StrSymbol * SymbolArray;
StrInputFilterAndState * InputFilterAndStateArray;

#ifdef GTK_INTERFACE
/* used for the editor */
StrEditRung EditDatas;
StrArithmExpr * EditArithmExpr;
#endif


// Default sizes values
// and variable used to store parameters before malloc()/init_rt_thread done!
// After init, we used it again to store the current configuration modifications !!!
// The real values allocated are in InfosGene->GeneralParams.SizesInfos...
StrGeneralParams GeneralParamsMirror; /* = {
	.SizesInfos.nbr_rungs = NBR_RUNGS_DEF,
	.SizesInfos.nbr_bits = NBR_BITS_DEF,
	.SizesInfos.nbr_words = NBR_WORDS_DEF,
#ifdef OLD_TIMERS_MONOS_SUPPORT
	.SizesInfos.nbr_timers = NBR_TIMERS_DEF,
	.SizesInfos.nbr_monostables = NBR_MONOSTABLES_DEF,
#endif
	.SizesInfos.nbr_counters = NBR_COUNTERS_DEF,
	.SizesInfos.nbr_timers_iec = NBR_TIMERS_IEC_DEF,
	.SizesInfos.nbr_phys_inputs = NBR_PHYS_INPUTS_DEF,
	.SizesInfos.nbr_phys_outputs = NBR_PHYS_OUTPUTS_DEF,
	.SizesInfos.nbr_arithm_expr = NBR_ARITHM_EXPR_DEF,
	.SizesInfos.nbr_sections = NBR_SECTIONS_DEF,
	.SizesInfos.nbr_symbols = NBR_SYMBOLS_DEF,
	.SizesInfos.nbr_phys_words_inputs = NBR_PHYS_WORDS_INPUTS_DEF,
	.SizesInfos.nbr_phys_words_outputs = NBR_PHYS_WORDS_OUTPUTS_DEF,
	.PeriodMilliSecsTaskLogic = PERIODIC_REFRESH_MS_DEF,
	.PeriodMilliSecsTaskScanInputs = PERIODIC_REFRESH_MS_INPUTS_DEF,
	.RealInputsOutputsOnlyOnTarget = FALSE
};*/

//v0.9.5, created a function to be called before loading another project
//(important to have correct default values, if some parameters not saved in older project...)
void InitGeneralParamsMirror( void )
{
	GeneralParamsMirror.SizesInfos.nbr_rungs = NBR_RUNGS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_bits = NBR_BITS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_words = NBR_WORDS_DEF;
#ifdef OLD_TIMERS_MONOS_SUPPORT
	GeneralParamsMirror.SizesInfos.nbr_timers = NBR_TIMERS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_monostables = NBR_MONOSTABLES_DEF;
#endif
	GeneralParamsMirror.SizesInfos.nbr_counters = NBR_COUNTERS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_timers_iec = NBR_TIMERS_IEC_DEF;
	GeneralParamsMirror.SizesInfos.nbr_phys_inputs = NBR_PHYS_INPUTS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_phys_outputs = NBR_PHYS_OUTPUTS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_arithm_expr = NBR_ARITHM_EXPR_DEF;
	GeneralParamsMirror.SizesInfos.nbr_sections = NBR_SECTIONS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_symbols = NBR_SYMBOLS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_phys_words_inputs = NBR_PHYS_WORDS_INPUTS_DEF;
	GeneralParamsMirror.SizesInfos.nbr_phys_words_outputs = NBR_PHYS_WORDS_OUTPUTS_DEF;
	GeneralParamsMirror.PeriodMilliSecsTaskLogic = PERIODIC_REFRESH_MS_DEF;
	GeneralParamsMirror.PeriodMilliSecsTaskScanInputs = PERIODIC_REFRESH_MS_INPUTS_DEF;
	GeneralParamsMirror.RealInputsOutputsOnlyOnTarget = FALSE;
}

void InitProjectProperties( void )
{
	char BuffCurrTime[ 30 ];
	GetCurrentAscTime( BuffCurrTime );
	InfosGene->ProjectProperties.ProjectName[ 0 ] = '\0';
	InfosGene->ProjectProperties.ParamVersion[ 0 ] = '0';
	InfosGene->ProjectProperties.ParamVersion[ 1 ] = '\0';
	InfosGene->ProjectProperties.ParamAuthor[ 0 ] = '\0';
	strcpy( InfosGene->ProjectProperties.ParamCreaDate, BuffCurrTime );
	strcpy( InfosGene->ProjectProperties.ParamModifDate, BuffCurrTime );
}

void InitInfosGene( void )
{
	InfosGene->LadderState = STATE_LOADING;
	InfosGene->UnderCalculationPleaseWait = FALSE;
	InfosGene->LadderStoppedToRunBack = FALSE;

	InfosGene->CmdRefreshVarsBits = FALSE;

	InfosGene->BlockWidth = BLOCK_WIDTH_DEF;
	InfosGene->BlockHeight = BLOCK_HEIGHT_DEF;
	InfosGene->PageWidth = 0;
	InfosGene->PageHeight = 0;
	InfosGene->TopRungDisplayed = 0;
	InfosGene->OffsetHiddenTopRungDisplayed = 0;
	InfosGene->OffsetCurrentRungDisplayed = 0;
	InfosGene->VScrollValue = 0;
	InfosGene->HScrollValue = 0;
	InfosGene->HeaderLabelCommentHeight = BLOCK_HEIGHT_DEF*65/100;

	InfosGene->DurationOfLastScan = -1; // unknow value, to do not display!
	InfosGene->CurrentSection = 0;

	InfosGene->AskConfirmationToQuit = FALSE;
	InfosGene->HasBeenModifiedForExitCode = FALSE;
	InfosGene->DisplaySymbols = TRUE;

	InfosGene->AskToConfHardInputs = FALSE;
	InfosGene->AskToConfHardOutputs = FALSE;
	InfosGene->LogContentModified = FALSE;
	InfosGene->DefaultLogListModified = FALSE;
	InfosGene->HardwareErrMsgToDisplay[ 0 ] = '\0'; //no error for now!
	
}

void InitInfosGUI( void )
{
	int ScanIt;
	InfosGUI->TargetMonitor.RemoteConnected = FALSE;
	InfosGUI->TargetMonitor.PreviousRemoteConnected = FALSE;
	InfosGUI->TargetMonitor.RemoteAdrIP[ 0 ] = '\0';
	InfosGUI->TargetMonitor.RemoteWithSerialPort[ 0 ] = '\0';
	InfosGUI->TargetMonitor.RemoteWithSerialSpeed = 115200;
	
	InfosGUI->TargetMonitor.RemoteFileTransfer = FALSE;
	InfosGUI->TargetMonitor.PreviousRemoteFileTransfer = FALSE;
	InfosGUI->TargetMonitor.TransferFileNum = -1;
	InfosGUI->TargetMonitor.TransferFileIsSend = FALSE;
	
	InfosGUI->TargetMonitor.AskTargetToSetState = -1;
	InfosGUI->TargetMonitor.AskTargetToReset = -1;
	InfosGUI->TargetMonitor.AskTargetToSetClockTime = -1;
	InfosGUI->TargetMonitor.AskTargetToReboot = -1;
	InfosGUI->TargetMonitor.AskTargetToGetTargetInfos = -1;
	InfosGUI->TargetMonitor.AskTargetToGetProjectProperties = -1;
	
	InfosGUI->TargetMonitor.AskTargetForThisManualFrame = NULL;
	
	InfosGUI->TargetMonitor.CmdDisplayTargetInfosVersion = FALSE;
	InfosGUI->TargetMonitor.CmdDisplayTargetProjectProperties = FALSE;
	
	for( ScanIt=0; ScanIt<NBR_TYPE_BOOLS_SPY; ScanIt++ )
		InfosGUI->ValOffsetBoolVar[ ScanIt ] = 0;
	for( ScanIt=0; ScanIt<NBR_FREE_VAR_SPY; ScanIt++ )
	{
		InfosGUI->FreeVarSpy[ ScanIt ].VarType = VAR_MEM_WORD;
		InfosGUI->FreeVarSpy[ ScanIt ].VarNum = ScanIt;
		InfosGUI->FreeVarSpyDisplayFormat[ ScanIt ] = 0;
	}
	InfosGUI->NbrRungsDisplayedToMonitor = 0;
}

/* return TRUE if okay */
int ClassicLadder_AllocAll()
{

#ifndef RT_SUPPORT

	InfosGene = (StrInfosGene *)malloc( sizeof(StrInfosGene) );
	if (!InfosGene)
	{
		debug_printf("Failed to alloc InfosGene !\n");
		return FALSE;
	}
	// set sizes values before making the next allocs...
	memcpy( &InfosGene->GeneralParams, &GeneralParamsMirror, sizeof( StrGeneralParams ) );
#ifdef GTK_INTERFACE
	UpdateSizesOfConvVarNameTable( );
#endif

#ifdef GTK_INTERFACE
	InfosGUI = (StrInfosGUI *)malloc( sizeof(StrInfosGUI) );
	if (!InfosGUI)
	{
		debug_printf("Failed to alloc InfosGUI !\n");
		return FALSE;
	}
#else
	InfosGUI = NULL;
#endif

	RungArray = (StrRung *)malloc( NBR_RUNGS * sizeof(StrRung) );
	if (!RungArray)
	{
		debug_printf("Failed to alloc RungArray !\n");
		return FALSE;
	}
#ifdef OLD_TIMERS_MONOS_SUPPORT
	TimerArray = (StrTimer *)malloc( NBR_TIMERS * sizeof(StrTimer) );
	if (!TimerArray)
	{
		debug_printf("Failed to alloc TimerArray !\n");
		return FALSE;
	}
	MonostableArray = (StrMonostable *)malloc( NBR_MONOSTABLES * sizeof(StrMonostable) );
	if (!MonostableArray)
	{
		debug_printf("Failed to alloc MonostableArray !\n");
		return FALSE;
	}
#endif
	CounterArray = (StrCounter *)malloc( NBR_COUNTERS * sizeof(StrCounter) );
	if (!CounterArray)
	{
		debug_printf("Failed to alloc CounterArray !\n");
		return FALSE;
	}
	NewTimerArray = (StrTimerIEC *)malloc( NBR_TIMERS_IEC * sizeof(StrTimerIEC) );
	if (!NewTimerArray)
	{
		debug_printf("Failed to alloc NewTimerArray !\n");
		return FALSE;
	}
	VarArray = (TYPE_FOR_BOOL_VAR *)malloc( SIZE_VAR_ARRAY * sizeof(TYPE_FOR_BOOL_VAR) );
	if (!VarArray)
	{
		debug_printf("Failed to alloc VarArray !\n");
		return FALSE;
	}
	LogVarArray = (unsigned char *)malloc( SIZE_VAR_ARRAY * sizeof(unsigned char) );
	if (!LogVarArray)
	{
		debug_printf("Failed to alloc LogVarArray !\n");
		return FALSE;
	}
	VarWordArray = (int *)malloc( SIZE_VAR_WORD_ARRAY * sizeof(int) );
	if (!VarWordArray)
	{
		debug_printf("Failed to alloc VarWordArray !\n");
		return FALSE;
	}
	ArithmExpr = (StrArithmExpr *)malloc( NBR_ARITHM_EXPR * sizeof(StrArithmExpr) );
	if (!ArithmExpr)
	{
		debug_printf("Failed to alloc ArithmExpr !\n");
		return FALSE;
	}
	SectionArray = (StrSection *)malloc( NBR_SECTIONS * sizeof(StrSection) );
	if (!SectionArray)
	{
		debug_printf("Failed to alloc SectionArray !\n");
		return FALSE;
	}
#ifdef SEQUENTIAL_SUPPORT
	Sequential = (StrSequential *)malloc( sizeof(StrSequential) );
	if (!Sequential)
	{
		debug_printf("Failed to alloc Sequential !\n");
		return FALSE;
	}
#endif
	SymbolArray = (StrSymbol *)malloc( NBR_SYMBOLS * sizeof(StrSymbol) );
	if (!SymbolArray)
	{
		debug_printf("Failed to alloc SymbolArray !\n");
		return FALSE;
	}
	InputFilterAndStateArray = (StrInputFilterAndState *)malloc( NBR_PHYS_INPUTS * sizeof(StrInputFilterAndState) );
	if (!InputFilterAndStateArray)
	{
		debug_printf("Failed to alloc InputFilterAndStateArray !\n");
		return FALSE;
	}

#else

	InfosGene = (StrInfosGene *)mbuff_alloc( "InfosGene", sizeof(StrInfosGene) );
	if (!InfosGene)
	{
		rt_debug_printf("Failed to alloc InfosGene shared memory !\n");
		rt_debug_printf("The real-time module must be inserted before...\n");
		rt_debug_printf("See the README to know how you must launch the real-time version !\n");
		return FALSE;
	}
	// get sizes before making the next allocs...
	memcpy( &InfosGene->GeneralParams, &GeneralParamsMirror, sizeof( StrGeneralParams ) );
	// get RT module parameters
	CopySizesInfosFromModuleParams( );

	RungArray = (StrRung *)mbuff_alloc( "Rungs", NBR_RUNGS * sizeof(StrRung) );
	if (!RungArray)
	{
		rt_debug_printf("Failed to alloc RungArray shared memory !\n");
		return FALSE;
	}
#ifdef OLD_TIMERS_MONOS_SUPPORT
	TimerArray = (StrTimer *)mbuff_alloc( "Timers", NBR_TIMERS * sizeof(StrTimer) );
	if (!TimerArray)
	{
		rt_debug_printf("Failed to alloc TimerArray shared memory !\n");
		return FALSE;
	}
	MonostableArray = (StrMonostable *)mbuff_alloc( "Monostables", NBR_MONOSTABLES * sizeof(StrMonostable) );
	if (!MonostableArray)
	{
		rt_debug_printf("Failed to alloc MonostableArray shared memory !\n");
		return FALSE;
	}
#endif
	CounterArray = (StrCounter *)mbuff_alloc( "Counters", NBR_COUNTERS * sizeof(StrCounters) );
	if (!CounterArray)
	{
		rt_debug_printf("Failed to alloc CounterArray shared memory !\n");
		return FALSE;
	}
	NewTimerArray = (StrTimerIEC *)mbuff_alloc( "TimersIEC", NBR_TIMERS_IEC * sizeof(StrTimerIEC) );
	if (!NewTimerArray)
	{
		rt_debug_printf("Failed to alloc NewTimerArray shared memory !\n");
		return FALSE;
	}
	VarArray = (TYPE_FOR_BOOL_VAR *)mbuff_alloc( "VarsBits", SIZE_VAR_ARRAY * sizeof(TYPE_FOR_BOOL_VAR) );
	if (!VarArray)
	{
		rt_debug_printf("Failed to alloc VarArray shared memory !\n");
		return FALSE;
	}
	LogVarArray = (unsigned char *)mbuff_alloc( "LogVarsBits", SIZE_VAR_ARRAY * sizeof(unsigned char) );
	if (!LogVarArray)
	{
		rt_debug_printf("Failed to alloc LogVarArray shared memory !\n");
		return FALSE;
	}
	VarWordArray = (int *)mbuff_alloc( "VarWords", SIZE_VAR_WORD_ARRAY * sizeof(int) );
	if (!VarWordArray)
	{
		rt_debug_printf("Failed to alloc VarWordArray shared memory !\n");
		return FALSE;
	}
	ArithmExpr = (StrArithmExpr *)mbuff_alloc( "ArithmExpr", NBR_ARITHM_EXPR * sizeof(StrArithmExpr) );
	if (!ArithmExpr)
	{
		rt_debug_printf("Failed to alloc ArithmExpr shared memory !\n");
		return FALSE;
	}
	SectionArray = (StrSection *)mbuff_alloc( "Sections", NBR_SECTIONS * sizeof(StrSection) );
	if (!SectionArray)
	{
		rt_debug_printf("Failed to alloc SectionArray shared memory !\n");
		return FALSE;
	}
#ifdef SEQUENTIAL_SUPPORT
	Sequential = (StrSequential *)mbuff_alloc( "Sequential", sizeof(StrSequential) );
	if (!Sequential)
	{
		rt_debug_printf("Failed to alloc Sequential shared memory !\n");
		return FALSE;
	}
#endif
	SymbolArray = (StrSymbol *)mbuff_alloc( "Symbols", NBR_SYMBOL * sizeof(StrSymbol) );
	if (!SymbolArray)
	{
		rt_debug_printf("Failed to alloc SymbolArray shared memory !\n");
		return FALSE;
	}
	InputFilterAndStateArray = (StrInputFilterAndState *)mbuff_alloc( "InputFilterAndState", NBR_PHYS_INPUTS * sizeof(StrInputFilterAndState) );
	if (!InputFilterAndStateArray)
	{
		debug_printf("Failed to alloc InputFilterAndStateArray !\n");
		return FALSE;
	}

#endif

#ifdef GTK_INTERFACE
	EditArithmExpr = (StrArithmExpr *)malloc( NBR_ARITHM_EXPR * sizeof(StrArithmExpr) );
	if (!EditArithmExpr)
	{
		debug_printf("Failed to alloc EditArithmExpr !\n");
		return FALSE;
	}
#endif

	InitInfosGene( );
#ifdef GTK_INTERFACE
	InitInfosGUI( );
#endif

	ClassicLadder_InitAllDatas( );

	return TRUE;
}

void ClassicLadder_FreeAll( char CleanAndRemoveTmpDir )
{
	InfosGene->LadderState = STATE_LOADING;
#ifdef GTK_INTERFACE
	if (EditArithmExpr)
		free(EditArithmExpr);
#endif
#ifndef RT_SUPPORT
	if (RungArray)
		free(RungArray);
#ifdef OLD_TIMERS_MONOS_SUPPORT
	if (TimerArray)
		free(TimerArray);
	if (MonostableArray)
		free(MonostableArray);
#endif
	if (CounterArray)
		free(CounterArray);
	if (NewTimerArray)
		free(NewTimerArray);
	if (VarArray)
		free(VarArray);
	if (LogVarArray)
		free(LogVarArray);
	if (VarWordArray)
		free(VarWordArray);
	if (ArithmExpr)
		free(ArithmExpr);
#ifdef GTK_INTERFACE
	if ( InfosGUI )
		free( InfosGUI );
#endif
	if (InfosGene)
		free(InfosGene);
	if (SectionArray)
		free(SectionArray);
#ifdef SEQUENTIAL_SUPPORT
	if (Sequential)
		free(Sequential);
#endif
	if (SymbolArray)
		free(SymbolArray);
	if (InputFilterAndStateArray)
		free(InputFilterAndStateArray);
	if ( CleanAndRemoveTmpDir )
		CleanTmpLadderDirectory( TRUE/*RemoveTmpDirAtEnd*/ );
#else
	if (RungArray)
		mbuff_free("Rungs",RungArray);
#ifdef OLD_TIMERS_MONOS_SUPPORT
	if (TimerArray)
		mbuff_free("Timers",TimerArray);
	if (MonostableArray)
		mbuff_free("Monostables",MonostableArray);
#endif
	if (CounterArray)
		mbuff_free("Counters",CounterArray);
	if (NewTimerArray)
		mbuff_free("TimersIEC",NewTimerArray);
	if (VarArray)
		mbuff_free("VarsBits",VarArray);
	if (LogVarArray)
		mbuff_free("LogVarsBits",LogVarArray);
	if (VarWordArray)
		mbuff_free("VarWords",VarWordArray);
	if (ArithmExpr)
		mbuff_free("ArithmExpr",ArithmExpr);
	if (InfosGene)
		mbuff_free("InfosGene",InfosGene);
	if (SectionArray)
		mbuff_free("Sections",SectionArray);
#ifdef SEQUENTIAL_SUPPORT
	if (Sequential)
		mbuff_free("Sequential",Sequential);
#endif
	if (SymbolArray)
		mbuff_free("Symbols",SymbolArray);
	if (InputFilterAndStateArray)
		mbuff_free("InputFilterAndState",InputFilterAndStateArray);
#endif
}

void ClassicLadder_InitAllDatas( void )
{
	InitProjectProperties( );
	InitGeneralParamsMirror( );
	InitIOConf( );
	InitVars( FALSE/*DoLogEvents*/ );
#ifdef OLD_TIMERS_MONOS_SUPPORT
	InitTimers();
	InitMonostables();
#endif
	InitCounters();
	InitTimersIEC();
	InitArithmExpr();
	InitRungs();
	InitSections( );
#ifdef SEQUENTIAL_SUPPORT
	InitSequential( );
#endif
	//added in v0.9.1, was forgotten...
	InitModbusMasterParams( );
	InitSymbols( );
	InitSystemVars( TRUE );

#ifdef COMPLETE_PLC
	InitLog( );
	InitVarsArrayLogTags( );
#endif

	InfosGene->AskConfirmationToQuit = FALSE;
	InfosGene->HasBeenModifiedForExitCode = FALSE;

}

